﻿using stdCall.Models;
using System;
using System.Collections;

namespace stdCall.MyRandom
{
    /// <summary>
    /// 核心算法类
    /// </summary>
    class Caculator
    {
        public static int RandomStdNum = 2;

        /// <summary>
        /// 按算法获取一个可怜的学生
        /// </summary>
        /// <param name="calllist">包含点名次数的学生列表</param>
        /// <returns>学生</returns>
        public static Student getAPoorStdNum(ArrayList calllist)
        {
            int index= decideFinally(calllist, randomFirstly(calllist.Count));
            Student std=(Student)calllist[index];
            new StudentsManager().getStudentByNum(std.Number).UnluckyCallNum++;
            return std;
        }

        /// <summary>
        /// 初始随机产生RandomStdNum个学生索引
        /// </summary>
        /// <param name="range">随机数范围</param>
        /// <returns>RandomStdNum个学生索引数组</returns>
        public static int[] randomFirstly(int range)
        {
            int[] s=new int[RandomStdNum];
            for (int i = 0; i < RandomStdNum; i++)
            {
                s[i] = -1;
            }
                s = getRandomNum(RandomStdNum, 0, range);
            return s;
        }

        /// <summary>
        /// 按公平算法决定最终的倒霉鬼索引
        /// </summary>
        /// <param name="calllist">包含点名次数的学生列表</param>
        /// <param name="students">初始随机产生的学生索引数组</param>
        /// <returns>最终倒霉鬼索引</returns>
        public static int decideFinally(ArrayList calllist,int []students)
        {
            int luckiestStudent = 0;
            int fairness = 1000;
            for (int i = 0; i < RandomStdNum; i++)
            {
                ArrayList ca = new ArrayList();
                foreach (Student std in calllist)
                {
                    ca.Add(new Student(std.Number,std.Name,std.UnluckyCallNum));
                }
                int index = students[i];
                ((Student)(ca[index])).UnluckyCallNum++;
                if (computeUnlucky(ca) < fairness)
                {
                    luckiestStudent = students[i];
                    fairness = computeUnlucky(ca);
                }
            }
            return luckiestStudent;
        }

        /// <summary>
        /// 计算公平值，各个学生倒霉值的平方的和
        /// </summary>
        /// <param name="calllist">包含点名次数的学生列表</param>
        /// <returns>公平值</returns>
        public static int computeUnlucky(ArrayList calllist)
        {
            int result = 0;
            foreach(Student std in calllist){
                result += std.UnluckyCallNum * std.UnluckyCallNum;
            }
            return result;
        }

        /// <summary>
        /// 随机产生num个数
        /// </summary>
        /// <param name="num"></param>
        /// <param name="minValue">范围最小值（包含）</param>
        /// <param name="maxValue">范围最大值（不包含）</param>
        /// <returns></returns>
        private static int[] getRandomNum(int num, int minValue, int maxValue)
        {
            Random ra = new Random(unchecked((int)DateTime.Now.Ticks));
            int[] arrNum = new int[num];
            int tmp = 0;
            for (int i = 0; i <= num - 1; i++)
            {
                tmp = ra.Next(minValue, maxValue); //随机取数
                arrNum[i] = getNum(arrNum, tmp, minValue, maxValue, ra); //取出值赋到数组中
            }
            return arrNum;
        }

        /// <summary>
        /// 递归，确保随机不重复
        /// </summary>
        /// <param name="arrNum"></param>
        /// <param name="tmp"></param>
        /// <param name="minValue"></param>
        /// <param name="maxValue"></param>
        /// <param name="ra"></param>
        /// <returns></returns>
        private static int getNum(int[] arrNum, int tmp, int minValue, int maxValue, Random ra)
        {
            int n = 0;
            while (n <= arrNum.Length - 1)
            {
                if (arrNum[n] == tmp) //利用循环判断是否有重复
                {
                    tmp = ra.Next(minValue, maxValue); //重新随机获取。
                    getNum(arrNum, tmp, minValue, maxValue, ra);//递归:如果取出来的数字和已取得的数字有重复就重新随机获取。
                }
                n++;
            }
            return tmp;
        }
    }
}
